﻿using AMS.Common.ToolChains.xxHash;
using AMS.Services.DomainModels;
using OA.Infrastructure.Abstractions;
using OA.Infrastructure.DomainModels.Message;
using OA.Infrastructure.Extensions;
using OA.Infrastructure.SignalR.Abstractions;
using OA.Infrastructure.WeCom;
using OA.Infrastructure.WeCom.Generator;

namespace AMS.Services.Impl;

public class ApprovalService : IApprovalService
{
    private readonly DbContext _context;

    private static readonly string _adminRoleCode = null!;

    private readonly ISignalRService _signalRService;
    private readonly ISystemSettingService _systemSettingService;
    private readonly IWeComService _weComService;

    internal static Func<DbContext, ICollection<ApprovalDetail>> fixedAssetsStorageApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> fixedAssetsConsumingApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> fixedAssetsReturnApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> freeAssetsStorageApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> freeAssetsConsumingApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> purchaseApprovalFlow;
    internal static Func<DbContext, ICollection<ApprovalDetail>> lossApprovalFlow;

    static ApprovalService()
    {
        using var scope = App.Services.CreateScope();
        using var ctx = scope.ServiceProvider.GetRequiredService<DbContext>();

        _adminRoleCode = ctx.Set<Role>().Select(n => new { n.Name, n.RoleCode }).First(n => n.Name == "管理员").RoleCode;

        static ICollection<ApprovalDetail> ExtractApprovers(IEnumerable<ApproverConfigDetail> details)
        {
            return details
                .OrderBy(x => x.Sort)
                .Select(x => new ApprovalDetail
                {
                    Sort = x.Sort,
                    Approver = x.Approver,
                    Status = ApprovalStatus.Pending
                }).ToArray();
        }

        #region Flow Initialize        
        fixedAssetsStorageApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.FixedAssetsStorageApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var hill = ctx.Set<User>().First(n => n.Account == "8006");
                var banana = ctx.Set<User>().First(n => n.Account == "8030");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = hill!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    },
                    new ApprovalDetail
                    {
                        Sort = 2,
                        Approver = banana!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.WaitingForLast,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };

        fixedAssetsConsumingApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.FixedAssetsConsumingApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var hill = ctx.Set<User>().First(n => n.Account == "8006");
                var banana = ctx.Set<User>().First(n => n.Account == "8030");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = hill!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    },
                    new ApprovalDetail
                    {
                        Sort = 2,
                        Approver = banana!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.WaitingForLast,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };

        fixedAssetsReturnApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.FixedAssetsReturnApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var hill = ctx.Set<User>().First(n => n.Account == "8006");
                var banana = ctx.Set<User>().First(n => n.Account == "8030");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = hill!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    },
                    new ApprovalDetail
                    {
                        Sort = 2,
                        Approver = banana!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.WaitingForLast,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };

        freeAssetsStorageApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.FreeAssetsStorageApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var sunny = ctx.Set<User>().First(n => n.Account == "8096");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = sunny!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    }
                };
            }


            return ExtractApprovers(cfg.ApproverDetails);
        };

        freeAssetsConsumingApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.FreeAssetsConsumingApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var sunny = ctx.Set<User>().First(n => n.Account == "8096");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = sunny!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };

        purchaseApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.PurchaseApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var sunny = ctx.Set<User>().First(n => n.Account == "8096");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = sunny!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };

        lossApprovalFlow = (ctx) =>
        {
            var cfg = ctx.Set<ApproverConfig>()
                .Include(x => x.ApproverDetails).ThenInclude(x => x.Approver)
                .FirstOrDefault(x => x.Key == RegisteredApprovalFlows.LossApprovalFlowDefinition.Key);

            if (cfg is null)
            {
                var hill = ctx.Set<User>().First(n => n.Account == "8006");

                return new List<ApprovalDetail>
                {
                    new ApprovalDetail
                    {
                        Sort = 1,
                        Approver = hill!,
                        Remark = "等待审批",
                        Status = ApprovalStatus.Pending,
                    }
                };
            }

            return ExtractApprovers(cfg.ApproverDetails);
        };
        #endregion
    }

    public ApprovalService(
        DbContext context,
        ISignalRService signalRService,
        ISystemSettingService systemSettingService,
        IWeComService weComService)
    {
        _context = context;
        _signalRService = signalRService;
        _systemSettingService = systemSettingService;
        _weComService = weComService;
    }

    public async Task<PageResult<Approval.QueryModel>> GetPageAsync(Approval.ConditionSelectorCondition condition, CancellationToken cancellationToken)
    {
        var result = new PageResult<Approval.QueryModel>();

        var currentUser = _context.CurrentUser();

        var accessExpression = currentUser.Account == "admin"
            ? (n => true)
            : (Expression<Func<Approval, bool>>?)(
                n => n.Committer.Id == currentUser.Id ||
                n.ApprovalDetails.Where(n => n.Approver.Id == currentUser.Id).Any());

        try
        {
            var expression = GetStatusSelectorCondition(condition);

            var data = await _context.Set<Approval>()
                .Include(m => m.ApprovalDetails).ThenInclude(n => n.Approver).ThenInclude(n => n.DirectLeader)
                .Include(m => m.ApprovalDetails).ThenInclude(n => n.Approver).ThenInclude(n => n.Department)
                .Include(n => n.Committer).ThenInclude(n => n.DirectLeader)
                .Include(n => n.Committer).ThenInclude(n => n.Department)
                .Include(n => n.Committer).ThenInclude(n => n.Roles)
                .Where(accessExpression)
                .Where(expression)
                .OrderByDescending(n => n.CreatedDate)
                .Skip((condition.PageNum - 1) * condition.PageSize)
                .Take(condition.PageSize)
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = data.Select(x => GetQueryModel(x));

            result.PageNum = condition.PageNum;

            result.PageSize = condition.PageSize;

            result.Total = await _context.Set<Approval>().Where(accessExpression).CountAsync(expression, cancellationToken);

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    private static Expression<Func<Approval, bool>> GetStatusSelectorCondition(Approval.ConditionSelectorCondition condition)
    {
        Expression<Func<Approval, bool>>? expression = null;

        if (condition.SelectedApprovalStatus is not null)
        {
            Expression<Func<Approval, bool>>? selectedApprovalStatus = null;
            selectedApprovalStatus = x => condition.SelectedApprovalStatus == x.Status;
            expression = expression?.And(selectedApprovalStatus) ?? selectedApprovalStatus;
        }

        if (condition.SelectedApprovalType is not null)
        {
            Expression<Func<Approval, bool>>? selectedApprovalType = null;
            selectedApprovalType = x => condition.SelectedApprovalType == x.Type;
            expression = expression?.And(selectedApprovalType) ?? selectedApprovalType;
        }

        if (condition.SelectedAssetsType is not null)
        {
            Expression<Func<Approval, bool>>? selectedAssetsType = null;
            selectedAssetsType = x => condition.SelectedAssetsType == x.AssetsType;
            expression = expression?.And(selectedAssetsType) ?? selectedAssetsType;
        }

        var createDateSelectorCondition = new Approval.CreatedDateSelectorCondition()
        {
            BeginDate = condition.CreatedDateSelectorBeginDate,
            EndDate = condition.CreatedDateSelectorEndDate,
        };

        var createdDateSelectorExpression = GetCreatedDateSelectorCondition(createDateSelectorCondition);

        if (createdDateSelectorExpression is not null)
        {
            expression = expression?.And(createdDateSelectorExpression) ?? createdDateSelectorExpression;
        }

        return expression ?? (x => true);
    }

    private static Expression<Func<Approval, bool>>? GetCreatedDateSelectorCondition(Approval.CreatedDateSelectorCondition condition)
    {
        Expression<Func<Approval, bool>>? expression = null;

        if (condition.BeginDate is not null)
        {
            Expression<Func<Approval, bool>>? beginDateSelector = null;
            beginDateSelector = x => x.CreatedDate >= condition.BeginDate.Value;
            expression = expression?.And(beginDateSelector) ?? beginDateSelector;
        }

        if (condition.EndDate is not null)
        {
            Expression<Func<Approval, bool>>? endDateSelector = null;
            endDateSelector = x => x.CreatedDate <= condition.EndDate.Value;
            expression = expression?.And(endDateSelector) ?? endDateSelector;
        }

        return expression;
    }

    public async Task<OperationalResult> CreateApprovalAsync(
        User committer,
        int formId,
        ApprovalType approvalType,
        AssetsType assetsType,
        string? remark,
        Func<DbContext, ICollection<ApprovalDetail>> factory,
        CancellationToken cancellationToken)
    {
        var result = new OperationalResult();

        var approval = new Approval
        {
            Type = approvalType,
            FormId = formId,
            AssetsType = assetsType,
            Committer = committer,
            ApprovalDetails = factory(_context),
            Remark = remark,
            Status = ApprovalStatus.Pending,
        };

        await _context.Set<Approval>().AddAsync(approval, cancellationToken);

        var affectedRows = await _context.SaveChangesAsync(cancellationToken);

        result.Status = affectedRows > 0 ? OperationalResult.SUCCESS : OperationalResult.FAILURE;

        if (result.Status == OperationalResult.SUCCESS)
        {
            var type = ConvertToApprovalTypeName(approvalType);

            await _signalRService.SendToGroupAsync($"收到来自{committer.Name}的{type}申请，请及时审批~", _adminRoleCode, cancellationToken);

            var firstApprover = approval.ApprovalDetails.First()!.Approver;

            if (await CanSendMessage(cancellationToken))
            {
                await SendApprovalCardAsync(firstApprover.UserId, approval, cancellationToken);
            }
        }

        return result;
    }

    public async Task<OperationalResult> PassAsync(int id, CancellationToken cancellationToken)
    {
        var result = new OperationalResult();
        var currenrUser = _context.CurrentUser();

        var approval = await _context.Set<Approval>()
            .Include(n => n.Committer)
            .Include(n => n.ApprovalDetails)
            .ThenInclude(n => n.Approver)
            .FirstOrDefaultAsync(n => n.Id == id, cancellationToken);

        if (approval is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "不存在该审批记录";

            return result;
        }

        var currentApprovalDetail = approval.ApprovalDetails.FirstOrDefault(n => n.Status == ApprovalStatus.Pending);

        if (currentApprovalDetail is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = $"不存在当前审批明细记录";

            return result;
        }

        var currentOrder = currentApprovalDetail.Sort;
        var nextDetail = approval.ApprovalDetails.FirstOrDefault(n => n.Sort == currentOrder + 1);

        if (currenrUser.Account == "admin")
        {
            approval.ApprovalDetails.ToList().ForEach(x => x.Status = ApprovalStatus.Passed);
        }
        else
        {
            currentApprovalDetail.Status = ApprovalStatus.Passed;

            if (nextDetail is not null)
            {
                nextDetail.Status = ApprovalStatus.Pending;
            }
        }

        if (approval.ApprovalDetails.All(n => n.Status == ApprovalStatus.Passed))
        {
            approval.Status = ApprovalStatus.Passed;

            try
            {
                await ChangeFormStatusAsync(approval, cancellationToken);
            }
            catch (Exception ex)
            {
                result.Status = OperationalResult.ERROR;
                result.Message = ex.Message;

                return result;
            }
        }

        _context.Set<Approval>().Update(approval);
        await _context.SaveChangesAsync(cancellationToken);

        var wecomService = App.Services.GetRequiredService<IWeComService>();

        var canSendMessage = await CanSendMessage(cancellationToken);

        if (nextDetail is not null)
        {
            var nextApprover = nextDetail.Approver;
            if (canSendMessage)
            {
                await SendApprovalCardAsync(nextApprover.UserId, approval, cancellationToken);
            }
        }
        else
        {
            if (canSendMessage)
            {
                _ = await wecomService.SendTextMessageAsync(approval.Committer.UserId, $"您提交的{ConvertToApprovalTypeName(approval.Type)}申请已经审批通过~");
            }
        }

        result.Message = "您已审批通过";

        return result;
    }

    public async Task<OperationalResult> RejectAsync(int id, string remark, CancellationToken cancellationToken)
    {
        var result = new OperationalResult();
        var currenrUser = _context.CurrentUser();

        var approval = await _context.Set<Approval>()
            .Include(n => n.Committer)
            .Include(n => n.ApprovalDetails)
            .ThenInclude(n => n.Approver)
            .FirstOrDefaultAsync(n => n.Id == id, cancellationToken);

        if (approval is null)
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var currentApprovalDetail = approval.ApprovalDetails.FirstOrDefault(n => n.Status == ApprovalStatus.Pending);

        if (currentApprovalDetail is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = $"不存在当前审批明细记录";

            return result;
        }

        currentApprovalDetail.Status = ApprovalStatus.Rejected;
        currentApprovalDetail.Remark = remark;
        approval.Status = ApprovalStatus.Rejected;

        try
        {
            await ChangeFormStatusAsync(approval, cancellationToken);
        }
        catch (Exception ex)
        {
            result.Status = OperationalResult.ERROR;
            result.Message = ex.Message;

            return result;
        }

        _context.Set<Approval>().Update(approval);
        await _context.SaveChangesAsync(cancellationToken);

        var wecomService = App.Services.GetRequiredService<IWeComService>();

        _ = await wecomService.SendTextMessageAsync(approval.Committer.UserId, $"您提交的{ConvertToApprovalTypeName(approval.Type)}申请已被 {currentApprovalDetail.Approver.Name} 驳回，请知悉~");

        result.Message = "您已驳回审批";

        return result;
    }

    private async Task ChangeFormStatusAsync(Approval approval, CancellationToken cancellationToken = default)
    {
        try
        {
            switch (approval.Type)
            {
                case ApprovalType.Storage:
                    switch (approval.AssetsType)
                    {
                        case AssetsType.Consumable:
                            await ProcessFreeAssetsStorage(approval, cancellationToken);
                            break;
                        case AssetsType.Durable:
                            await ProcessFixedAssetsStorage(approval, cancellationToken);
                            break;
                    }
                    break;
                case ApprovalType.Consuming:
                    switch (approval.AssetsType)
                    {
                        case AssetsType.Consumable:
                            await ProcessFreeAssetsConsuming(approval, cancellationToken);
                            break;
                        case AssetsType.Durable:
                            await ProcessFixedAssetsConsuming(approval, cancellationToken);
                            break;
                    }
                    break;
                case ApprovalType.Return:
                    switch (approval.AssetsType)
                    {
                        case AssetsType.Consumable:
                            break;
                        case AssetsType.Durable:
                            await ProcessAssetsReturn(approval, cancellationToken);
                            break;
                    }
                    break;
                case ApprovalType.Requisition:
                    await ProcessAssetsRequisition(approval, cancellationToken);
                    break;
                case ApprovalType.Loss:
                    await ProcessAssetsLoss(approval, cancellationToken);
                    break;
            }
        }
        catch
        {
            throw;
        }
    }

    private async Task<WeComButtonTemplateCardEngine> GenerateBusinessTemplateCardEngineAsync(Approval approval, CancellationToken cancellationToken = default)
    {
        var engine = TemplateCardGenerateEngineFactory.GetButtonTemplateCardEngine(true, false);

        var target = ConvertToAssetsTypeName(approval.AssetsType);
        var bizType = ConvertToApprovalTypeName(approval.Type);

        var formFrom = approval.Committer.UserId == "admin" ? "系统管理员" : $"$userName={approval.Committer.UserId}$";
        if (approval.Committer.UserId == "admin")
        {
            engine.AddHoriztontalContentItemForText("申请人", approval.Committer.Name);
        }
        else
        {
            engine.AddHoriztontalContentItemForUserDetail("申请人", approval.Committer.Name, approval.Committer.UserId);
        }

        switch (approval.Type)
        {
            case ApprovalType.Storage:
                {
                    switch (approval.AssetsType)
                    {
                        case AssetsType.Consumable:
                            {
                                var form = await _context.Set<FreeAssetsStorage>()
                                    .Include(x => x.Supplier)
                                    .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                                if (form is null)
                                {
                                    throw new InvalidOperationException("表单不存在");
                                }

                                engine.WithActionMenu("附加功能")
                                .AddActionMenuItem(new TemplateCardActionMenuItem
                                {
                                    Text = "通知本人",
                                    Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                                })
                                .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                                .AddHoriztontalContentItemForText("资产名称", form.Name)
                                .AddHoriztontalContentItemForText("入库数量", form.Count.ToString())
                                .AddHoriztontalContentItemForText("供应商", form.Supplier.Name);

                                if (form.Description is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("描述", form.Description);
                                }

                                if (form.Remark is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("备注", form.Remark);
                                }
                            }
                            break;
                        case AssetsType.Durable:
                            {
                                var form = await _context.Set<FixedAssetsStorage>()
                                    .Include(x => x.Category)
                                    .Include(x => x.Supplier)
                                    .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                                if (form is null)
                                {
                                    throw new InvalidOperationException("表单不存在");
                                }

                                engine.WithActionMenu("附加功能")
                                .AddActionMenuItem(new TemplateCardActionMenuItem
                                {
                                    Text = "通知本人",
                                    Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                                })
                                .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                                .AddHoriztontalContentItemForText("资产名称", form.Name)
                                .AddHoriztontalContentItemForText("资产类别", form.Category.Name)
                                .AddHoriztontalContentItemForText("供应商", form.Supplier.Name);

                                if (form.Description is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("描述", form.Description);
                                }

                                if (form.Remark is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("备注", form.Remark);
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
                break;
            case ApprovalType.Consuming:
                {
                    switch (approval.AssetsType)
                    {
                        case AssetsType.Consumable:
                            {
                                var form = await _context.Set<FreeAssetsConsuming>()
                                    .Include(x => x.Assets).ThenInclude(x => x.Supplier)
                                    .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                                if (form is null)
                                {
                                    throw new InvalidOperationException("表单不存在");
                                }

                                engine.WithActionMenu("附加功能")
                                .AddActionMenuItem(new TemplateCardActionMenuItem
                                {
                                    Text = "通知本人",
                                    Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                                })
                                .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                                .AddHoriztontalContentItemForText("资产名称", form.Assets.Name)
                                .AddHoriztontalContentItemForText("供应商", form.Assets.Supplier.Name)
                                .AddHoriztontalContentItemForText("批次", form.Assets.Batch)
                                .AddHoriztontalContentItemForText("领用数量", form.Count.ToString());

                                if (form.Remark is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("备注", form.Remark);
                                }
                            }
                            break;
                        case AssetsType.Durable:
                            {
                                var form = await _context.Set<FixedAssetsConsuming>()
                                    .Include(x => x.Assets).ThenInclude(x => x.Supplier)
                                    .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                                if (form is null)
                                {
                                    throw new InvalidOperationException("表单不存在");
                                }

                                engine.WithActionMenu("附加功能")
                                .AddActionMenuItem(new TemplateCardActionMenuItem
                                {
                                    Text = "通知本人",
                                    Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                                })
                                .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                                .AddHoriztontalContentItemForText("资产序列号", form.Assets.SerialNo)
                                .AddHoriztontalContentItemForText("资产名称", form.Assets.Name)
                                .AddHoriztontalContentItemForText("供应商", form.Assets.Supplier.Name);

                                if (form.UseLocation is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("使用地点", form.UseLocation);
                                }

                                if (form.Remark is not null)
                                {
                                    engine.AddHoriztontalContentItemForText("备注", form.Remark);
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
                break;
            case ApprovalType.Return:
                {
                    var form = await _context.Set<FixedAssetsConsuming>()
                        .Include(x => x.Assets)
                        .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                    if (form is null)
                    {
                        throw new InvalidOperationException("表单不存在");
                    }

                    engine.WithActionMenu("附加功能")
                    .AddActionMenuItem(new TemplateCardActionMenuItem
                    {
                        Text = "通知本人",
                        Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                    })
                    .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                    .AddHoriztontalContentItemForText("资产名称", form.Assets.Name);

                    if (form.UseLocation is not null)
                    {
                        engine.AddHoriztontalContentItemForText("使用地点", form.UseLocation);
                    }
                }
                break;
            case ApprovalType.Requisition:
                {
                    var form = await _context.Set<Purchase>()
                        .FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                    if (form is null)
                    {
                        throw new InvalidOperationException("表单不存在");
                    }

                    engine.WithActionMenu("附加功能")
                    .AddActionMenuItem(new TemplateCardActionMenuItem
                    {
                        Text = "通知本人",
                        Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                    })
                    .WithTitle($"资产{bizType}审批", $"来自{formFrom}的资产{bizType}审批")
                    .WithQuoteArea("采购详情", form.ToString());

                    if (form.Remark is not null)
                    {
                        engine.AddHoriztontalContentItemForText("采购事由", form.Remark.LimitLength(30));
                    }
                }
                break;
            case ApprovalType.Loss:
                {
                    var form = await _context.Set<FixedAssetsLoss>().FirstOrDefaultAsync(x => x.Id == approval.FormId, cancellationToken);

                    if (form is null)
                    {
                        throw new InvalidOperationException("表单不存在");
                    }

                    engine.WithActionMenu("附加功能")
                    .AddActionMenuItem(new TemplateCardActionMenuItem
                    {
                        Text = "通知本人",
                        Key = WeComCallbackEvents.TemplateCardApproveNoticeSelfEventKey
                    })
                    .WithTitle($"{target}{bizType}审批", $"来自{formFrom}的{target}{bizType}审批")
                    .WithQuoteArea("报损详情", form.ToString());

                    if (form.Remark is not null)
                    {
                        engine.AddHoriztontalContentItemForText("报损原因", form.Remark.LimitLength(30));
                    }
                }
                break;
            default:
                break;
        }

        return engine;
    }

    private static string ConvertToApprovalTypeName(ApprovalType type)
    {
        return type switch
        {
            ApprovalType.Storage => "入库",
            ApprovalType.Consuming => "领用",
            ApprovalType.Return => "归还",
            ApprovalType.Requisition => "采购",
            ApprovalType.Loss => "报损",
            _ => throw new NotImplementedException(),
        };
    }

    private static string ConvertToAssetsTypeName(AssetsType type)
    {
        return type switch
        {
            AssetsType.Consumable => "易耗品资产",
            AssetsType.Durable => "固定资产",
            _ => throw new NotImplementedException(),
        };
    }

    private static Approval.QueryModel GetQueryModel(Approval approval)
    {
        return new Approval.QueryModel
        {
            Id = approval.Id,
            CreatedDate = approval.CreatedDate,
            LastModifiedDate = approval.LastModifiedDate,
            Type = approval.Type,
            AssetsType = approval.AssetsType,
            ApprovalDetails = approval.ApprovalDetails.Select(x => ApprovalDetailService.GetQueryModel(x)),
            Remark = approval.Remark,
            Committer = DefinitionServiceExtensions.GetUserQueryModel(approval.Committer),
            Status = approval.Status,
        };
    }

    private async Task ProcessFreeAssetsStorage(Approval approval, CancellationToken cancellationToken = default)
    {
        var assetsStorage = await _context.Set<FreeAssetsStorage>()
            .Include(x => x.Category)
            .Include(x => x.Supplier)
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        assetsStorage.Status = approval.Status;

        if (approval.Status == ApprovalStatus.Passed)
        {
            var assetsRepo = await _context.Set<FreeAssetsRepo>().FirstOrDefaultAsync(n =>
                n.Assets.Name == assetsStorage.Name &&
                n.Assets.Category == assetsStorage.Category &&
                n.Assets.Supplier == assetsStorage.Supplier &&
                n.Assets.Batch == assetsStorage.Batch,
                cancellationToken);

            if (assetsRepo is not null)
            {
                assetsRepo.Stock += assetsStorage.Count;

                assetsRepo.Status = assetsRepo.Status == AssetsStatus.OutOfStock ? AssetsStatus.Normal : assetsRepo.Status;

                _context.Set<FreeAssetsRepo>().Update(assetsRepo);
            }
            else
            {
                var newAssets = new FreeAssets
                {
                    Name = assetsStorage.Name,
                    Category = assetsStorage.Category,
                    Supplier = assetsStorage.Supplier,
                    Batch = assetsStorage.Batch,
                    Description = assetsStorage.Description
                };

                var newAssetsRepo = new FreeAssetsRepo
                {
                    Assets = newAssets,
                    Stock = assetsStorage.Count
                };

                await _context.Set<FreeAssetsRepo>().AddAsync(newAssetsRepo, cancellationToken);
            }
        }

        _context.Set<FreeAssetsStorage>().Update(assetsStorage);
    }

    private async Task ProcessFixedAssetsStorage(Approval approval, CancellationToken cancellationToken = default)
    {
        var assetsStorage = await _context.Set<FixedAssetsStorage>()
            .Include(x => x.Category)
            .Include(x => x.Supplier)
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        assetsStorage.Status = approval.Status;

        if (approval.Status == ApprovalStatus.Passed)
        {
            var newAssets = new FixedAssets
            {
                SerialNo = AssetsSerialNumberGenerator.Generate("**"),
                Name = assetsStorage.Name,
                Specs = assetsStorage.Specs,
                Category = assetsStorage.Category,
                Univalent = assetsStorage.Univalent,
                Supplier = assetsStorage.Supplier,
                Description = assetsStorage.Description
            };

            var newAssetsRepo = new FixedAssetsRepo
            {
                Assets = newAssets,
                StorageLocation = assetsStorage.StorageLocation,
                PurchaseDate = assetsStorage.PurchaseDate,
            };

            await _context.Set<FixedAssetsRepo>().AddAsync(newAssetsRepo, cancellationToken);
        }

        _context.Set<FixedAssetsStorage>().Update(assetsStorage);
    }

    private async Task ProcessFreeAssetsConsuming(Approval approval, CancellationToken cancellationToken = default)
    {
        var assetsConsuming = await _context.Set<FreeAssetsConsuming>()
            .Include(n => n.Assets)
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        assetsConsuming.Status = approval.Status;

        if (approval.Status == ApprovalStatus.Passed)
        {
            var assetsRepo = await _context.Set<FreeAssetsRepo>()
                .Include(n => n.Assets)
                .FirstOrDefaultAsync(n => n.Assets.Id == assetsConsuming.Assets.Id, cancellationToken);

            if (assetsRepo is not null)
            {
                if (assetsRepo.Stock >= assetsConsuming.Count)
                {
                    assetsRepo.Stock -= assetsConsuming.Count;

                    _context.Set<FreeAssetsRepo>().Update(assetsRepo);
                }
                else
                {
                    throw new Exception("无法通过（领用数量超过现有库存）");
                }
            }
        }

        _context.Set<FreeAssetsConsuming>().Update(assetsConsuming);
    }

    private async Task ProcessFixedAssetsConsuming(Approval approval, CancellationToken cancellationToken = default)
    {
        var assetsConsuming = await _context.Set<FixedAssetsConsuming>()
            .Include(n => n.Assets)
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        assetsConsuming.Status = approval.Status;

        if (approval.Status == ApprovalStatus.Passed)
        {
            var assetsRepo = await _context.Set<FixedAssetsRepo>()
                .Include(n => n.Assets)
                .FirstOrDefaultAsync(n => n.Assets.Id == assetsConsuming.Assets.Id, cancellationToken);

            if (assetsRepo is not null)
            {
                assetsRepo.Owner = assetsRepo.Owner is null
                    ? assetsConsuming.Consumer
                    : throw new Exception($"无法通过（{assetsConsuming.Assets.SerialNo}-{assetsConsuming.Assets.Name}已被领用）");

                assetsRepo.UseLocation = assetsConsuming.UseLocation;

                _context.Set<FixedAssetsRepo>().Update(assetsRepo);


            }
            else
            {
                throw new Exception("无法通过（资产不存在）");
            }

            assetsConsuming.Returning = false;
        }
        else
        {
            assetsConsuming.Returning = null;
        }

        _context.Set<FixedAssetsConsuming>().Update(assetsConsuming);
    }

    private async Task ProcessAssetsReturn(Approval approval, CancellationToken cancellationToken = default)
    {
        var assetsConsuming = await _context.Set<FixedAssetsConsuming>()
            .Include(n => n.Assets)
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        if (approval.Status == ApprovalStatus.Passed)
        {
            var assetsRepo = await _context.Set<FixedAssetsRepo>().FirstOrDefaultAsync(n => n.Assets.Id == assetsConsuming.Assets.Id, cancellationToken);

            if (assetsRepo is not null)
            {
                assetsRepo.Owner = null;
                assetsRepo.UseLocation = null;

                _context.Set<FixedAssetsRepo>().Update(assetsRepo);
            }
            else
            {
                throw new Exception("无法通过（资产库存信息失效，请联系管理员）");
            }

            assetsConsuming.Returning = null;

        }
        else
        {
            assetsConsuming.Returning = false;
        }

        _context.Set<FixedAssetsConsuming>().Update(assetsConsuming);
    }

    private async Task ProcessAssetsRequisition(Approval approval, CancellationToken cancellationToken = default)
    {
        var purchase = await _context.Set<Purchase>()
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        purchase.Status = approval.Status == ApprovalStatus.Passed ? PurchaseStatus.Appropriation : PurchaseStatus.Rejected;

        _context.Set<Purchase>().Update(purchase);
    }

    private async Task ProcessAssetsLoss(Approval approval, CancellationToken cancellationToken = default)
    {
        var loss = await _context.Set<FixedAssetsLoss>()
            .FirstAsync(n => n.Id == approval.FormId, cancellationToken);

        loss.Status = approval.Status == ApprovalStatus.Passed ? LossStatus.Fixing : LossStatus.Rejected;

        _context.Set<FixedAssetsLoss>().Update(loss);
    }

    private async Task<bool> CanSendMessage(CancellationToken cancellationToken = default)
    {
        var systemSettings = await _systemSettingService.GetAsync(cancellationToken);

        return systemSettings.Data.SendMessage;
    }

    private async Task SendApprovalCardAsync(string targetUserId, Approval approval, CancellationToken cancellationToken = default)
    {
        var engine = await GenerateBusinessTemplateCardEngineAsync(approval, cancellationToken);

        var card = engine
            .WithSource(new TemplateCardSource
            {
                Desc = "OA-资产管理系统",
                Desc_color = 0
            })
            .WithCardActionForUrl($"{_weComService.AppEntryUrl}/approval/list")
            .AddButtonForCallback("驳回", WeComCallbackEvents.TemplateCardApproveRejectEventKey, WeComTemplateCardButtonStyle.Dangerous)
            .AddButtonForCallback("通过", WeComCallbackEvents.TemplateCardApprovePassEventKey, WeComTemplateCardButtonStyle.Primary)
            .Generate();

        _ = await _weComService.SendButtonInteractionMessageAsync(targetUserId, card, approval.Id.ToString());
    }
}